/*
 * Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
 *
 * HDF is dual licensed: you can use it either under the terms of
 * the GPL, or the BSD license, at your option.
 * See the LICENSE file in the root of this repository for complete details.
 */

#include <stdlib.h>
#include <string.h>
#include "esp_err.h"
#include "uart.h"
#include "uart_types.h"
#include "uart_if.h"
#include "uart_core.h"
#include "osal_sem.h"
#include "hcs_macro.h"
#include "hdf_config_macro.h"
#include "hdf_log.h"

#define HDF_UART_TMO 1000
#define HDF_LOG_TAG uartDev
#define GPIO_MAX_LENGTH 32
#define UART_FIFO_MAX_BUFFER 2048
#define UART_DMA_RING_BUFFER_SIZE 256 // mast be 2^n
#define MAX_DEV_NAME_SIZE 32

#define UART_PIN_NUNS 4     // 串口引脚配置个数
#define MAX_UART_NUMS 3     // 最大串口个数
#define UART_RX_BUFF_SIZE 512
#define UART_TX_BUFF_SIZE 512

#define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
#define PLATFORM_UART_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), uart_config)
#define HDF_GPIO_FIND_SOURCE(node, name)                                                                        \
    do {                                                                                                        \
        if (strcmp(HCS_PROP(node, match_attr), name) == 0) {                                                    \
            int cur_uart_gpio_pin[] = HCS_ARRAYS(HCS_PROP(node, uart_gpio_pin));                                \
            struct UartAttrSourceStr cur_uart_attr = HCS_ARRAYS(HCS_PROP(node, uart_attr));                     \
            all_uart_config[g_uart_nums].uart_port = HCS_PROP(node, uart_port);                                 \
            all_uart_config[g_uart_nums].baudrate = HCS_PROP(node, baudrate);                                   \
            all_uart_config[g_uart_nums].uart_pin[0] = cur_uart_gpio_pin[0];                                   \
            all_uart_config[g_uart_nums].uart_pin[1] = cur_uart_gpio_pin[1];                                   \
            all_uart_config[g_uart_nums].uart_pin[2] = cur_uart_gpio_pin[2];                                   \
            all_uart_config[g_uart_nums].uart_pin[3] = cur_uart_gpio_pin[3];                                   \
            all_uart_config[g_uart_nums].data_bits = GetWordLengthFromStr(cur_uart_attr.data_bits);             \
            all_uart_config[g_uart_nums].parity = GetParityFromStr(cur_uart_attr.parity);                       \
            all_uart_config[g_uart_nums].stop_bits = GetStopBitsFromStr(cur_uart_attr.stop_bits);               \
            all_uart_config[g_uart_nums].hw_flowcontrol = GetHwFlowControlFromStr(cur_uart_attr.hw_flowcontrol);\
            HDF_LOGE("----- UART Index [%d] Config -----", g_uart_nums);                                        \
            HDF_LOGE("uart_port = %d", all_uart_config[g_uart_nums].uart_port);                                 \
            HDF_LOGE("baudrate = %d", all_uart_config[g_uart_nums].baudrate);                                   \
            HDF_LOGE("Uart_Pin = [%d,%d,%d,%d]", all_uart_config[g_uart_nums].uart_pin[0],                    \
                     all_uart_config[g_uart_nums].uart_pin[1], all_uart_config[g_uart_nums].uart_pin[2],       \
                     all_uart_config[g_uart_nums].uart_pin[3] );                                                \
            HDF_LOGE("data_bits = %s[%d]", cur_uart_attr.data_bits,                                         \
                     all_uart_config[g_uart_nums].data_bits);                                                 \
            HDF_LOGE("parity = %s[%d]", cur_uart_attr.parity, all_uart_config[g_uart_nums].parity);             \
            HDF_LOGE("stop_bits = %s[%d]", cur_uart_attr.stop_bits, all_uart_config[g_uart_nums].stop_bits);    \
            HDF_LOGE("hw_flowcontrol = %s[%d]", cur_uart_attr.hw_flowcontrol,                                   \
                     all_uart_config[g_uart_nums].hw_flowcontrol);                                              \
            g_uart_nums++;                                                                                      \
        }\
    } while (0);

static int32_t UartDriverBind(struct HdfDeviceObject* device);
static int32_t UartDriverInit(struct HdfDeviceObject* device);
static void UartDriverRelease(struct HdfDeviceObject* device);

struct HdfDriverEntry g_UartDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "ESP32_HDF_UART",
    .Bind = UartDriverBind,
    .Init = UartDriverInit,
    .Release = UartDriverRelease,
};

HDF_INIT(g_UartDriverEntry);

static int32_t UartHostDevInit(struct UartHost* host);
static int32_t UartHostDevDeinit(struct UartHost* host);
static int32_t UartHostDevWrite(struct UartHost* host, uint8_t* data, uint32_t size);
static int32_t UartHostDevSetBaud(struct UartHost* host, uint32_t baudRate);
static int32_t UartHostDevGetBaud(struct UartHost* host, uint32_t* baudRate);
static int32_t UartHostDevRead(struct UartHost* host, uint8_t* data, uint32_t size);
static int32_t UartHostDevSetAttribute(struct UartHost* host, struct UartAttribute* attribute);
static int32_t UartHostDevGetAttribute(struct UartHost* host, struct UartAttribute* attribute);
static int32_t UartHostDevSetTransMode(struct UartHost* host, enum UartTransMode mode);


struct UartHostMethod g_uartHostMethod = {
    .Init = UartHostDevInit,
    .Deinit = UartHostDevDeinit,
    .Read = UartHostDevRead,
    .Write = UartHostDevWrite,
    .SetBaud = UartHostDevSetBaud,
    .GetBaud = UartHostDevGetBaud,
    .SetAttribute = UartHostDevSetAttribute,
    .GetAttribute = UartHostDevGetAttribute,
    .SetTransMode = UartHostDevSetTransMode,
};

struct UartAttrSourceStr {
    char* data_bits;
    char* parity;
    char* stop_bits;
    char* hw_flowcontrol;
};

struct UartAttrSourceValue {
    int uart_port;
    int baudrate;
    int uart_pin[UART_PIN_NUNS];
    int data_bits;
    int parity;
    int stop_bits;
    int hw_flowcontrol;
};

static int g_uart_nums = 0;        // hcs文件中定义的Uart个数
struct UartAttrSourceValue all_uart_config[MAX_UART_NUMS] = { 0 };


static int GetWordLengthFromStr(const char* str)
{
    if (!strcmp(str, "UART_DATA_5_BITS")) {
        return UART_DATA_5_BITS;
    }
    else if (!strcmp(str, "UART_DATA_6_BITS")) {
        return UART_DATA_6_BITS;
    }
    else if (!strcmp(str, "UART_DATA_7_BITS")) {
        return UART_DATA_7_BITS;
    }
    return UART_DATA_8_BITS;
}

static int GetParityFromStr(const char* str)
{
    if (!strcmp(str, "UART_PARITY_EVEN")) {
        return UART_PARITY_EVEN;
    }
    else if (!strcmp(str, "UART_PARITY_ODD")) {
        return UART_PARITY_ODD;
    }
    return UART_PARITY_DISABLE;
}

static int GetStopBitsFromStr(const char* str)
{
    if (!strcmp(str, "UART_STOP_BITS_1_5")) {
        return UART_STOP_BITS_1_5;
    }
    else if (!strcmp(str, "UART_STOP_BITS_2")) {
        return UART_STOP_BITS_2;
    }
    return UART_STOP_BITS_1;
}

static int GetHwFlowControlFromStr(const char* str)
{
    if (!strcmp(str, "UART_HW_FLOWCTRL_RTS")) {
        return UART_HW_FLOWCTRL_RTS;
    }
    else if (!strcmp(str, "UART_HW_FLOWCTRL_CTS")) {
        return UART_HW_FLOWCTRL_CTS;
    }
    else if (!strcmp(str, "UART_HW_FLOWCTRL_CTS_RTS")) {
        return UART_HW_FLOWCTRL_CTS_RTS;
    }
    return UART_HW_FLOWCTRL_DISABLE;
}

static int32_t AttachUartDevice(struct UartHost* uartHost, struct HdfDeviceObject* device)
{
    int32_t ret;
    if (device == NULL) {
        HDF_LOGE("%s: property is NULL", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    HCS_FOREACH_CHILD_VARGS(PLATFORM_UART_CONFIG, HDF_GPIO_FIND_SOURCE, device->deviceMatchAttr);

    device->priv = &all_uart_config;
    uartHost->num = g_uart_nums;

    return HDF_SUCCESS;
}

static int32_t UartDriverBind(struct HdfDeviceObject* device)
{
    if (device == NULL) {
        HDF_LOGE("%s: invalid parameter", __func__);
        return HDF_ERR_INVALID_PARAM;
    }
    struct UartHost* devService = UartHostCreate(device);
    if (devService == NULL) {
        HDF_LOGE("%s: UartHostCreate fail!", __func__);
        return HDF_FAILURE;
    }
    HDF_LOGI("%s: UartHostCreate success!", __func__);
    return HDF_SUCCESS;
}

static void UartDriverRelease(struct HdfDeviceObject* device)
{
    struct UartHost* host = NULL;
    if (device == NULL) {
        HDF_LOGE("%s: device is NULL!", __func__);
        return;
    }

    host = UartHostFromDevice(device);
    if (host == NULL) {
        HDF_LOGE("%s: host is null", __func__);
        return;
    }

    if (host->priv != NULL) {
        OsalMemFree(host->priv);
        host->priv = NULL;
    }
}

static int32_t UartDriverInit(struct HdfDeviceObject* device)
{
    HDF_LOGI("Enter %s:", __func__);
    int32_t ret;
    struct UartHost* host = NULL;

    if (device == NULL) {
        HDF_LOGE("%s: device is NULL", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    host = UartHostFromDevice(device);
    if (host == NULL) {
        HDF_LOGE("%s: host is NULL", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    ret = AttachUartDevice(host, device);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: attach error", __func__);
        return HDF_FAILURE;
    }
    host->method = &g_uartHostMethod;
    return ret;
}

/* UartHostMethod implementations */
static int32_t UartHostDevInit(struct UartHost* host)
{
    int ret;
    HDF_LOGI("%s: Enter\r\n", __func__);
    if (host == NULL) {
        HDF_LOGE("%s: invalid parameter", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    for (int i = 0; i < g_uart_nums; i++) {
        uart_config_t uartConfig = { 0 };
        uartConfig.baud_rate = all_uart_config[i].baudrate;
        uartConfig.data_bits = all_uart_config[i].data_bits;
        uartConfig.parity = all_uart_config[i].parity;
        uartConfig.stop_bits = all_uart_config[i].stop_bits;
        uartConfig.flow_ctrl = all_uart_config[i].hw_flowcontrol;
        if (0x01 & uartConfig.flow_ctrl) {
            uartConfig.rx_flow_ctrl_thresh = 122;
        }
        uart_param_config(all_uart_config[i].uart_port, &uartConfig);
        ret = uart_set_pin(all_uart_config[i].uart_port, all_uart_config[i].uart_pin[0],
                           all_uart_config[i].uart_pin[1], all_uart_config[i].uart_pin[2], 
                           all_uart_config[i].uart_pin[3]);
        if (ret != 0) {
            HDF_LOGE("uart_set_pin failed ret=0x%X\n", ret);
            return HDF_FAILURE;
        }

        ret = uart_driver_install(all_uart_config[i].uart_port, UART_RX_BUFF_SIZE, UART_TX_BUFF_SIZE, 0, NULL, 0);
        if (ret != 0) {
            HDF_LOGE("uart_driver_install failed ret=0x%X\n", ret); 
            return HDF_FAILURE;
        }
    }
    return HDF_SUCCESS;
}

static int32_t UartHostDevDeinit(struct UartHost* host)
{
    int ret;
    for (int i = 0; i < g_uart_nums; i++) {
        ret = uart_driver_delete(all_uart_config[i].uart_port);
        if(ret != ESP_OK) {
            HDF_LOGE("%s: uart%d_driver_delete failed\n", i, __func__);
        }
    }
    return HDF_SUCCESS;
}

static int32_t UartHostDevWrite(struct UartHost* host, uint8_t* data, uint32_t size)
{
    HDF_LOGI("%s: Enter", __func__);
    return HDF_SUCCESS;
}

static int32_t UartHostDevRead(struct UartHost* host, uint8_t* data, uint32_t size)
{
    HDF_LOGI("%s: Enter", __func__);
    return HDF_SUCCESS;
}

static int32_t UartHostDevSetBaud(struct UartHost* host, uint32_t baudRate)
{
    HDF_LOGI("%s: Enter", __func__);
    return HDF_SUCCESS;
}

static int32_t UartHostDevGetBaud(struct UartHost* host, uint32_t* baudRate)
{
    HDF_LOGI("%s: Enter", __func__);
    return HDF_SUCCESS;
}

static int32_t UartHostDevSetAttribute(struct UartHost* host, struct UartAttribute* attribute)
{
    HDF_LOGI("%s: Enter", __func__);
    return HDF_SUCCESS;
}

static int32_t UartHostDevGetAttribute(struct UartHost* host, struct UartAttribute* attribute)
{
    HDF_LOGI("%s: Enter", __func__);
    return HDF_SUCCESS;
}

static int32_t UartHostDevSetTransMode(struct UartHost* host, enum UartTransMode mode)
{
    HDF_LOGI("%s: Enter", __func__);
    return HDF_SUCCESS;
}